using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Transactions;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.ConnectionPool;
using OracleInternal.ServiceObjects;

namespace OracleInternal.MTS
{
	internal class MTSRMManager
	{
		static MTSRMManager()
		{
			if (ConfigBaseClass.m_recoveryServicePort <= 0)
			{
				ConfigBaseClass.m_recoveryServicePort = 2030;
			}
			if (ConfigBaseClass.m_dtcTxnTimeout == 0)
			{
				ConfigBaseClass.m_dtcTxnTimeout = 120u;
			}
			if (ConfigBaseClass.m_recoveryServiceHost.Length > TransXID.MAXRRECOHOSTNAME_LEN && IPAddress.TryParse(ConfigBaseClass.m_recoveryServiceHost, out var address) && address.AddressFamily == AddressFamily.InterNetworkV6)
			{
				ConfigBaseClass.m_recoveryServiceHost = address.ToString();
				if (ConfigBaseClass.m_recoveryServiceHost.Length > TransXID.MAXRRECOHOSTNAME_LEN)
				{
					ConfigBaseClass.m_recoveryServiceHost = CompressedIPv6(address);
				}
			}
			if ((DTCDebugConfig.s_DTCDbgEvt & DTCDebugEvent.MTSConfig) == DTCDebugEvent.MTSConfig)
			{
				Console.WriteLine("DTC_DEBUG_EVENT = " + DTCDebugConfig.s_DTCDbgEvt);
				Console.WriteLine("MTS Config value: Host = " + ConfigBaseClass.m_recoveryServiceHost);
				Console.WriteLine("MTS Config value: Port = " + ConfigBaseClass.m_recoveryServicePort);
				Console.WriteLine("MTS Config value: Transaction Time out = " + ConfigBaseClass.m_dtcTxnTimeout);
				Console.WriteLine("MTS Config value: Is Use DTC DLL = " + ConfigBaseClass.m_dtcUseDTCDLL);
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.cctor, "DTC_DEBUG_EVENT = " + DTCDebugConfig.s_DTCDbgEvt);
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.cctor, "MTS Config value: Host = " + ConfigBaseClass.m_recoveryServiceHost);
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.cctor, "MTS Config value: Port = " + ConfigBaseClass.m_recoveryServicePort);
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.cctor, "MTS Config value: Transaction Time out = " + ConfigBaseClass.m_dtcTxnTimeout);
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.cctor, "MTS Config value: Is Use DTC DLL = " + ConfigBaseClass.m_dtcUseDTCDLL);
			}
		}

		private static string CompressedIPv6(IPAddress address)
		{
			byte[] addressBytes = address.GetAddressBytes();
			StringBuilder stringBuilder = new StringBuilder();
			ushort num = 0;
			byte[] array = new byte[2];
			for (int i = 0; i < addressBytes.Length; i += 2)
			{
				array[0] = addressBytes[i + 1];
				array[1] = addressBytes[i];
				num = BitConverter.ToUInt16(array, 0);
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(":");
				}
				if (num != 0)
				{
					stringBuilder.AppendFormat("{0:x}", num);
				}
				else
				{
					stringBuilder.Append("0");
				}
			}
			return stringBuilder.ToString();
		}

		private static Exception HandleException(Exception ex)
		{
			OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.HandleException, ex);
			if (ex.GetType() == typeof(OracleException))
			{
				if (((OracleException)ex).Errors.Count > 0)
				{
					if (((OracleException)ex).Errors[0].Number == 161)
					{
						return new ConfigurationErrorsException(ex.Message, new OracleException(ResourceStringConstants.MTS_INVALID_CONFIG_VALUES, string.Empty, string.Empty, OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.MTS_INVALID_CONFIG_VALUES)));
					}
					return ex;
				}
				return ex;
			}
			return ex;
		}

		private static void CheckPromotionRule(OracleConnectionImpl connImpl)
		{
		}

		internal static void EnlistPromotedTransaction(OracleConnectionImpl connImpl, Transaction txn, MTSTxnRM txnRM, MTSTxnBranch txnBranch, Guid sysTxnXID)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.EnlistPromotedTransaction, "Local TxnID =  " + txn.TransactionInformation.LocalIdentifier + "\t TxnID = " + txn.TransactionInformation.DistributedIdentifier.ToString() + " using Conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
			}
			try
			{
				CheckPromotionRule(connImpl);
				if (txnBranch.m_bNew)
				{
					txnBranch.Set(txn.TransactionInformation.LocalIdentifier, sysTxnXID, txn.IsolationLevel);
				}
				txnBranch.PromoteDistributedTransaction(connImpl);
				txnRM.AddBranch(connImpl, txnBranch, sysTxnXID);
			}
			catch (Exception ex)
			{
				throw HandleException(ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.EnlistPromotedTransaction, "Local TxnID =  " + txn.TransactionInformation.LocalIdentifier + "\t TxnID = " + txnBranch.TxnID?.ToString() + " using Conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
				}
			}
		}

		internal static void CCPEnlistDistributedTxnToSysTxn(OracleConnectionImpl connImpl, Transaction txn, MTSTxnRM txnRM, MTSTxnBranch txnBranch)
		{
			if (ProviderConfig.m_bTraceLevelPrivate_NoTrace)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistDistributedTxnToSysTxn, "Local TxnID =  " + txn.TransactionInformation.LocalIdentifier + "\t TxnID = " + txn.TransactionInformation.DistributedIdentifier.ToString() + " using Conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
			}
			throw new PlatformNotSupportedException();
		}

		internal static void CCPEnlistTransaction(OracleConnectionImpl connImpl, Transaction transaction, OracleConnection connRefForCriteria)
		{
			if (ProviderConfig.m_bTraceLevelPrivate_NoTrace)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, "Local TxnID =  " + transaction.TransactionInformation.LocalIdentifier + " using conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
			}
			if (transaction.IsolationLevel != 0 && transaction.IsolationLevel != IsolationLevel.ReadCommitted)
			{
				throw new ArgumentException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_INVALID_ISO_LEVEL), "isolationLevel");
			}
			MTSTxnRM rM = OracleConnectionDispenser<OraclePoolManager, OraclePool, OracleConnectionImpl>.GetRM(connImpl.m_cs, connRefForCriteria, transaction, connImpl);
			MTSTxnBranch txnBranch = rM.GetTxnBranch(connImpl.m_cs, connImpl.m_instanceName);
			if (txnBranch == null)
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, string.Format("Max branch limit reach ({0}).  Local Txn ID = {1}", rM.m_branchNum, transaction.TransactionInformation.LocalIdentifier, rM.m_txnAffInstanceName));
				}
				throw new OracleException(ResourceStringConstants.CON_MTS_ENLIST_FAIL, string.Empty, string.Empty, OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_MTS_ENLIST_FAIL));
			}
			CCPEnlistTransaction(connImpl, transaction, rM, txnBranch);
			if (ProviderConfig.m_bTraceLevelPrivate_NoTrace)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, $"[GetTxnBranch] (2) (txnid={transaction.TransactionInformation.LocalIdentifier}) (affinity={rM.m_txnAffInstanceName}) (rmid={rM.GetHashCode()}) (rmtxid={rM.m_txnLocalID}) (brid={txnBranch.GetHashCode()}) (brtxnid={txnBranch.m_txnLocalID})");
			}
		}

		internal static void CCPEnlistTransaction(OracleConnectionImpl connImpl, Transaction transaction, MTSTxnRM txnRM, MTSTxnBranch txnBranch)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4352, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, "Local TxnID =  " + transaction.TransactionInformation.LocalIdentifier + " using conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
			}
			try
			{
				connImpl.m_localTxnId = transaction.TransactionInformation.LocalIdentifier;
				PSPEManager pSPEManager = null;
				if ((connImpl.m_cs.m_promotableTransaction == PromotableTransaction.Local || (connImpl.m_cs.m_promotableTransaction == PromotableTransaction.Promotable && connImpl.IsSupportPromotableTransaction)) && transaction.EnlistPromotableSinglePhase(pSPEManager = PSPEManager.Create(connImpl, transaction, txnRM, txnBranch)))
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.MTS, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, "Register PSPE Local Txn:\tLocal Txn ID = " + transaction.TransactionInformation.LocalIdentifier + " using Conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
					}
				}
				else
				{
					pSPEManager = null;
					CCPEnlistDistributedTxnToSysTxn(connImpl, transaction, txnRM, txnBranch);
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268439552, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, ex);
				connImpl.m_localTxnId = string.Empty;
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)4608, OracleTraceClassName.MTSRMManager, OracleTraceFuncName.CCPEnlistTransaction, " Local TxnID : " + transaction.TransactionInformation.LocalIdentifier + " using conn ID = " + connImpl.m_endUserSessionId + " to DBInst = " + connImpl.m_instanceName);
				}
			}
		}
	}
}
